#include <stdio.h>
#include <stdint.h>
#include "gic.h"
#include "intc.h"

typedef void (*vector_fn_t)(void);

static vector_fn_t m_vector[1024];

__asm static GIC_Type *get_gic_base(void)
{
	MRC p15, 4, R0, c15, c0, 0
	BX LR
}

#define GIC get_gic_base()

void intc_init(void)
{
	uint32_t i;
	uint32_t reg_number = (GIC->D_TYPER & 0x1F) + 1;
	for (i = 0; i < reg_number; i++)
	{
		GIC->D_ICENABLER[i] = 0xFFFFFFFFUL;
	}
	GIC->C_PMR = (0xFFUL << (8 - __GIC_PRIO_BITS)) & 0xFFUL;
	GIC->C_BPR = 7 - __GIC_PRIO_BITS;
	GIC->D_CTLR = 1UL;
	GIC->C_CTLR = 1UL;
}

void intc_set_handler(int irq, void (*handler)(void))
{
	m_vector[irq] = handler;
}

void intc_set_priority(int irq, int prio)
{
	GIC->D_IPRIORITYR[((uint32_t)irq)] = (uint8_t)((prio << (8UL - __GIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}

void intc_set_pending(int irq)
{
	GIC->D_SGIR = 1 << 16 | irq;
}

void intc_clear_pending(int irq)
{

}

void intc_enable_irq(int irq)
{
	GIC->D_ISENABLER[((uint32_t)irq) >> 5] = (uint32_t)(1UL << (((uint32_t)irq) & 0x1FUL));
}

void intc_disable_irq(int irq)
{
	GIC->D_ICENABLER[((uint32_t)irq) >> 5] = (uint32_t)(1UL << (((uint32_t)irq) & 0x1FUL));
}

void intc_handler(void)
{
	int irq = GIC->C_IAR & 0x3FFUL;
	if(m_vector[irq])
	{
		m_vector[irq]();
	}
	GIC->C_EOIR = irq;
}
